package cn.ilikes.tools.nosql.jpa.metadatas.processor.processores;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import javax.persistence.Column;
import javax.persistence.Id;

import org.slf4j.Logger;

import cn.ilikes.tools.logs.Loggerfactory;
import cn.ilikes.tools.nosql.jpa.annotations.Save;
import cn.ilikes.tools.nosql.jpa.metadatas.EntityMetaData;
import cn.ilikes.tools.nosql.jpa.metadatas.elements.EntityFields;
import cn.ilikes.tools.nosql.jpa.metadatas.elements.JPAColumn;
import cn.ilikes.tools.nosql.jpa.metadatas.elements.JPAField;
import cn.ilikes.tools.nosql.jpa.metadatas.elements.Relation;
import cn.ilikes.tools.nosql.jpa.metadatas.processor.TableProcessor;
import cn.ilikes.tools.nosql.jpa.metadatas.processor.validators.EntityFieldValidator;
import cn.ilikes.tools.nosql.jpa.metadatas.processor.validators.EntityValidatorException;

public class EntityFieldElementProcessors extends ElementProcessors implements Processors {

	private static Logger logger = Loggerfactory.instance(EntityFieldElementProcessors.class);

	private EntityFieldValidator entityFieldValidator = new EntityFieldValidator();

	@Override
	public void validators(Class<?> clazz, EntityMetaData entityMetaData) throws EntityValidatorException {
		if (Loggerfactory.isdebug(logger))
			logger.debug("start  validators  entity  " + clazz.getName() + " table  field ");
		try {
			entityFieldValidator.entityValidator(clazz, entityMetaData);
		} catch (EntityValidatorException e) {
			throw new EntityValidatorException(e);
		}
	}

	@Override
	public void processors(Class<?> clazz, EntityMetaData metadata) throws ElementProcessorException {
		if (Loggerfactory.isdebug(logger))
			logger.debug("start  processors   entity  " + clazz.getName() + " table  field ");
		validators(clazz, metadata);
		Field[] fs = clazz.getDeclaredFields();
		for (Field f : fs) {
			String fieldName = f.getName();
			if (fieldName.startsWith("serialVersionUID"))
				continue;
			Id id = f.getAnnotation(Id.class);
			if (id != null) {
				processorsId(clazz, metadata, f, fieldName);
			} else {
				processorsField(clazz, metadata, f, fieldName);

			}
		}
	}

	private void processorsField(Class<?> clazz, EntityMetaData metadata, Field f, String fieldName) throws ElementProcessorException {
		EntityFields entityFields = (EntityFields) metadata.getEntityField(fieldName);
		if (entityFields == null) {
			//初始化
			entityFields = new EntityFields(fieldName, EntityFields.EntityFieldsType.RealocalKey, false, true);
			entityFields.setSave(false);
			JPAField jpafield = new JPAField(false);
			jpafield.setColumn(new JPAColumn(false));
			jpafield.setRelation(new Relation(false));
			entityFields.setjPAField(jpafield);
			entityFields.setField(f);
			GetSettMethod(clazz, entityFields, f);
			metadata.getEntityFields().put(fieldName, entityFields);
		}
		Column column = f.getAnnotation(Column.class);
		if (column != null) {
			TableProcessor.processorsIndexColumn(entityFields, f);
			processorsJPAColumn(entityFields, f);
		}

		Save save = f.getAnnotation(Save.class);
		if (save == null) {
			if (f.isAnnotationPresent(Column.class))
				entityFields.setSave(true);
		} else {
			entityFields.setSave(save.save());
		}
	}

	private void processorsId(Class<?> clazz, EntityMetaData metadata, Field f, String fieldName) throws ElementProcessorException {
		if (metadata.getEntityId() == null) {
			Column column = f.getAnnotation(Column.class);
			EntityFields entityFieldsId = new EntityFields(fieldName, EntityFields.EntityFieldsType.RealocalKey, true, false);
			entityFieldsId.setField(f);
			JPAField jpafield = new JPAField(true);
			String columnName = f.getName();
			if (column != null) {
				columnName = column.name();
				columnName = ((columnName == null || columnName.isEmpty()) ? f.getName() : columnName);
			}
			jpafield.setColumn(new JPAColumn(columnName));
			jpafield.setRelation(new Relation(false));
			entityFieldsId.setjPAField(jpafield);
			GetSettMethod(clazz, entityFieldsId, f);
			metadata.setEntityFieldsId(entityFieldsId);
			TableProcessor.processorsIndexColumn(entityFieldsId, f);
			metadata.getEntityFields().put(fieldName, entityFieldsId);
		}
	}

	private void processorsJPAColumn(EntityFields entityFields, Field f) {

		Column column = f.getAnnotation(Column.class);
		if (column == null)
			return;
		JPAField jpafield = new JPAField(true);
		String columnName = column.name();
		//set
		columnName = ((columnName == null || columnName.isEmpty()) ? f.getName() : columnName);
		JPAColumn column_ = new JPAColumn(columnName);
		jpafield.setColumn(column_);
		// Relation 
		Relation relation = new Relation(false);
		jpafield.setRelation(relation);
		//end
		entityFields.setjPAField(jpafield);

		if (Loggerfactory.isdebug(logger))
			logger.debug("start processors  jpa  column ; " + columnName + "  field :   " + f.getName() + "  relation  " + entityFields.getjPAField().getRelation().isAbleRelation());

	}

	private void GetSettMethod(Class<?> clazz, EntityFields entityFields, Field field) throws ElementProcessorException {
		String fieldName = field.getName();
		try {
			// 获得和属性对应的getXXX()方法的名字
			String firstLetter = fieldName.substring(0, 1).toUpperCase();
			String getMethodName = "get" + firstLetter + fieldName.substring(1);
			// 获得和属性对应的setXXX()方法的名字
			String setMethodName = "set" + firstLetter + fieldName.substring(1);

			// 获得和属性对应的getXXX()方法

			Method getMethod = clazz.getMethod(getMethodName, new Class[] {});
			// 获得和属性对应的setXXX()方法，使用filed对象的类型
			Method setMethod = clazz.getMethod(setMethodName, new Class[] { field.getType() });

			entityFields.setGetMethod(getMethod);

			entityFields.setSetMethod(setMethod);

		} catch (NoSuchMethodException e) {
			Loggerfactory.error(logger, e);
			throw new ElementProcessorException(e);
		} catch (SecurityException e) {
			Loggerfactory.error(logger, e);
			throw new ElementProcessorException(e);
		}
	}

}
